<?php 

/**
 * 依赖注入实现解藕
 * 1.依赖注入并不神性
 * 2.本质上来说,就是对工具类的实例化不在工作类中完成,而是在工作类之外,即客户端完成
 * 3.由于工具类实例化在客户端完成,所在在工作类中,必须要有接收器用来保存实例化的工具对象
 * 4.此时,用户就可以将在客户端已经实例化好的工具对象,以参数的方式直接传递给工作类的方法
 * 5.这种由外部直接将对象传入到当前工作类的方式,就叫依赖注入
 */

//数据库操作类
class Db
{
	//数据库连接
	public function connect()
	{
		return '数据库连接成功<br>';
	}
}

//数据验证类
class Validate
{
	//数据验证
	public function check()
	{
		return '数据验证成功<br>';
	}
}

//视图图
class View
{
	//内容输出
	public function display()
	{
		return '用户登录成功';
	}
}

//用户类
class User
{

	//用户登录操作
	public function login(Db $db, Validate $validate, View $view)
	{
		//实例化Db类并调用connect()连接数据库
		// $db = new Db();
		echo $db->connect();

		//实例化Validate类并调用check()进行数据验证
		// $validate = new Validate();
		echo $validate->check();

		//实例化视图类并调用display()显示运行结果
		// $view = new View();
		echo $view->display();
	}
}
//在客户端完成工具类的实例化(即工具类实例化前移)
$db = new Db();
$validate = new Validate();
$view = new View();

//创建User类
$user = new User();

//调用User对象的login方法进行登录操作
// echo $user->login();
// 将该类依赖的外部对象以参数方式注入到当前方法中,当然,推荐以构造器方式注入最方便
echo '<h3>用依赖注入进行解藕:</h3>';
echo $user->login($db, $validate, $view);

/**
 *  虽然将依赖类的实例化前移到客户端,但解决了类之间的依赖问题
 *  但是仍存在以下几个问题:
 * 1.为了使工作类User正常工具,必须事先在外部将所需要的类全部事先实例化;
 * 2.只要涉及实例化,就要求客户端(调用者)必须对这些依赖类的细节非常了解,例如参数与返回值
 *
 * 那么能不能让用户把实例化依赖类的步骤都省略掉呢?这样岂不是更好,更简单
 * 我们调用外部依赖类,只要给一个类名,以及一个创建该类实例的方法(构造器)就可以了呢?
 * 即: 我们只给出:  类名, 创建类实例的方法,其它一概不管
 * 下面我们通过的"容器技术"来这现这种傻瓜式的的解藕过程
 */


// 构造器中实现注入以简化代码
//用户类
class User
{
	protected $db = null;
	protected $validate = null;
	protected $view = null;

	public function __construct(Db $db, Validate $validate, View $view)
	{
		$this->db = $db;
		$this->validate = $validate;
		$this->view = $view;
	}

	//用户登录操作
	public function login()
	{
		//实例化Db类并调用connect()连接数据库
		echo $this->db->connect();

		//实例化Validate类并调用check()进行数据验证
		echo $this->validate->check();

		//实例化视图类并调用display()显示运行结果
		echo $this->view->display();
	}
}













